其他
如何让程序真正地在后台运行?
守护进程
$ jobs
[1]+ Running nohup ./hello &
$ shopt |grep onexit
huponexit on
如果你在你的Linux系统中执行下面的命令:
如何实现
调用umask设置文件模式,通常设置为0。为了便于后续创建文件,不使用继承而来的父进程的设置,需要设置新的权限掩码。 调用fork,创建子进程,并且父进程退出 调用setdid创建新的会话(一个或多个进程组的集合),由于当前进程不是一个进程组的组长,因此会创建一个新的会话,却成为组长进程,同时没有控制终端。 将当前工作目录切换为根目录。同样的,其工作目录可能是从父进程继承而来的,可以自己另立山头。 关闭不需要的文件描述符。同样的,可能从父进程继承了一些打开的文件描述符,而这些描述符可能再也不需要,因此可以关闭。 重定向标准输出,标准输入和标准错误到/dev/null(相关阅读:Linux下你还知道这些特殊文件?)
重新设置权限掩码,避免受父进程影响 创建新的会话,脱离终端 使用新的工作目录 关闭不需要的文件描述符 关闭标准输入,标准输出和标准错误
具体实现
//https://www.yanbinghu.com
#include<stdio.h>
#include<sys/resource.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
/*实现仅供参考,可根据实际情况调整*/
int daemonize()
{
/*清除文件权限掩码*/
umask(0);
/*父进程退出*/
pid_t pid;
if((pid=fork()) < 0)
{
/*for 出错*/
perror("fork error");
return -1;
}
else if(0 != pid)/*父进程*/
{
printf("father exit\n");
exit(0);
}
/*子进程,成为组长进程,并且摆脱终端*/
setsid();
/*修改工作目录*/
if(chdir("/") < 0)
{
perror("change dir failed");
return -1;
}
struct rlimit rl;
/*先获取文件描述符最大值*/
if(getrlimit(RLIMIT_NOFILE,&rl) < 0)
{
perror("get file decription failed");
return -1;
}
/*如果无限制,则设置为1024*/
if(rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
/*为了使得终端有输出,保留了文件描述符0,1,2;实际上父进程可能没有打开2以上的文件描述符*/
int i;
for(i = 3;i < rl.rlim_max;i++)
close(i);
return 0;
}
int main(void)
{
if(0 == daemonize())
{
printf("daemonize ok\n");
sleep(20);
}
else
{
printf("daemonize failed\n");
sleep(20);
}
return 0;
}
实际实现
int daemon(int nochdir, int noclose);
nochdir 为0时,表示修改其根目录为/,否则不变 noclose,为0时,表示将标准输入,标准输出,标准错误重定向到/dev/null。
//https://www.yanbinghu.com
#include<stdio.h>
#include<unistd.h>
int main(void)
{
if(0 == daemon(1,1))
{
printf("daemon ok\n");
sleep(20);
}
else
{
printf("daemon failed\n");
sleep(20);
}
return 0;
}
总结
创建子进程,父进程退出 创建新的会话,脱离终端
int nochdir, noclose;
{
int fd;
switch (fork())
{
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1)
{
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close (fd);
}
return (0);
}
相关精彩推荐